/****************************************/
/* Application.cpp			 			*/
/* Created on: Sep 4, 2011				*/
/* Copyright Playsoft 2011				*/
/* Released under GPL v2				*/
/****************************************/

#include "Application.h"
#include "Player.h"

//----------------------------------------------------------------------

Application * instance;

//----------------------------------------------------------------------

volatile bool runLoop = false;

void loop()
{
	runLoop = true;
}

//----------------------------------------------------------------------

void close()
{
	instance->running = false;
}

//----------------------------------------------------------------------

Application::Application() : 	running(true) , currentState(SPLASH) , currentGrowSpeed(0.5f) , currentHeight(0) ,
								growAcceleration(0.2f) , gravityAcceleration(0.4f) , FPS(30) , frameCounter(0) , m_Player(0x0)
{
	instance = this;

	allegro_init();
	install_keyboard();
	install_timer();

	install_joystick(JOY_TYPE_AUTODETECT);
	install_sound(DIGI_AUTODETECT, MIDI_NONE, "");

	LOCK_VARIABLE(runLoop);
	LOCK_FUNCTION(loop);

	install_int_ex(loop, BPS_TO_TIMER(FPS));

	set_color_depth(32);
    set_gfx_mode(GFX_AUTODETECT_WINDOWED,800,600,0,0);
    set_window_title("High Five: Beyond!");
    set_palette(default_palette);

    buffer = create_bitmap(SCREEN_W, SCREEN_H);

	intro = load_bmp("data/splash.bmp", default_palette );
	play = load_bmp("data/playsoft.bmp", default_palette );
	background = 0x0;

	set_close_button_callback( close );

	for(int i = 0 ; i < 4 ; i++)
		legs[i] = 0x0;

	for(int i = 0 ; i < 6 ; i++)
		flowers[i] = 0x0;

	Leg::init();
	bottom = new Bottom();

	jingle = load_sample("data/jingle.wav");
	lose = load_sample("data/lose.wav");
	start = load_sample("data/start.wav");

	srand ( time(NULL) );
}

//----------------------------------------------------------------------

Application::~Application()
{
	allegro_exit();
}

//----------------------------------------------------------------------

void Application::setState(State s)
{
	rest(50);
	clear_keybuf();
	rest(100);

	if(s == GAME)
	{
		if(background == 0x0)
			destroy_bitmap(background);

		std::string path = "data/bkg_" + intToString(rand() % 2 + 1) + ".bmp";
		background = load_bmp(path.c_str(), default_palette );

		if(m_Player == 0x0)
			delete m_Player;

		m_Player = new Player(30,100);

		for(int i=0 ; i < 6 ; i++)
		{
			if(flowers[i] != 0x0)
				delete flowers[i];

			flowers[i]=new  Flower(Flower::GROW,2,66+i*133,450);
		}

		for(int i=0 ; i < 4 ; i++)
		{
			if(legs[i] != 0x0)
			{
				delete legs[i];
				legs[i] = 0x0;
			}
		}

		currentGrowSpeed = 2.0f;
		currentHeight = 0.0f;
		frameCounter = 0;
	}
	else if(s == INTRO)
		play_sample(jingle, 255, 128, 1000, FALSE);
	else if(s == GAME_OVER)
		play_sample(lose, 255, 128, 1000, FALSE);

	currentState = s;
}

//----------------------------------------------------------------------

void Application::run()
{
	while(running)
	{
		clear(buffer);

		if(runLoop)
		{
			poll_joystick();

			update();
			runLoop = false;
			frameCounter++;
		}

		draw();

		blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
	}
}

//----------------------------------------------------------------------

void Application::cleanup()
{
	destroy_bitmap(buffer);
	destroy_bitmap(intro);
	destroy_bitmap(play);

	if(background == 0x0)
		destroy_bitmap(background);

	delete bottom;
	Leg::clear();
}

//----------------------------------------------------------------------

void Application::update()
{
	switch(currentState)
	{
		case SPLASH:
			updateSplash();
			break;

		case INTRO:
			updateIntro();
			break;

		case GAME:
			updateGame();
			break;

		case GAME_OVER:
			updateGameOver();
			break;
	}
}

//----------------------------------------------------------------------

void Application::draw()
{
	switch(currentState)
	{
		case SPLASH:
			drawSplash();
			break;

		case INTRO:
			drawIntro();
			break;

		case GAME:
			drawGame();
			break;

		case GAME_OVER:
			drawGameOver();
			break;
	}
}

//----------------------------------------------------------------------

std::string Application::intToString(int i)
{
	std::string s;
	std::stringstream out;
	out << i;
	return out.str();
}

//----------------------------------------------------------------------

void Application::updateSplash()
{
	if(frameCounter > 60)
		setState(INTRO);
}

//----------------------------------------------------------------------

void Application::drawSplash()
{
	rectfill(buffer, 0, 0, SCREEN_W, SCREEN_H, makecol(255,255,255));
	blit(play, buffer, 0, 0, 300, 160, 200, 280);
}

//----------------------------------------------------------------------

void Application::updateIntro()
{
	if(key[KEY_SPACE] || key[KEY_ENTER] || joy[0].button[9].b)
	{
		setState(GAME);
		play_sample(start, 255, 128, 1000, FALSE);
	}
}

//----------------------------------------------------------------------

void Application::drawIntro()
{
	blit(intro, buffer, 0, 0, 0, 0, 800, 600);

	if(frameCounter > 15)
		textout_centre_ex(buffer,font,"Press START",SCREEN_W/2,SCREEN_H/2 ,makecol(255,255,255),-1);

	if(frameCounter > 30)
		frameCounter = 0;
}

//----------------------------------------------------------------------

void Application::updateGame()
{
	//Keys
	if(key[KEY_LEFT] || joy[0].stick[0].axis[0].d1 || joy[0].stick[2].axis[0].d1)
		m_Player->GoLeft();

	if(key[KEY_RIGHT] || joy[0].stick[0].axis[0].d2 || joy[0].stick[2].axis[0].d2)
		m_Player->GoRight();

	if(key[KEY_SPACE] || joy[0].button[2].b || joy[0].button[3].b)
		m_Player->Jump();

	if(key[KEY_ESC])
		setState(GAME_OVER);

	currentHeight += currentGrowSpeed;
	statusString = "Current Height: " + intToString((int)currentHeight/10);

	if(frameCounter % 90 == 0)
		currentGrowSpeed += growAcceleration;

	m_Player->Update(currentGrowSpeed,flowers,legs);

	for(int i =0; i<6;i++)
	{
		flowers[i]->updateHeight();
	}

	if( (m_Player->m_yPosition > SCREEN_H - 90) || (m_Player->lives == 0))
		setState(GAME_OVER);

	bottom->update();

	for(int i = 0 ; i < 4 ; i++)
	{
		if(legs[i] != 0x0)
		{
			legs[i]->update(currentGrowSpeed);

			if(legs[i]->getHit())
			{
				delete legs[i];
				legs[i] = 0x0;
			}
		}
		else if(rand() % 300 == 0)
		{
			legs[i] = new Leg(gravityAcceleration);
		}
	}
}

//----------------------------------------------------------------------

void Application::drawGame()
{
	int shift = (int)currentHeight % 256;

	for(int i = -1; i <= SCREEN_H/256 ; i++)
	{
		blit(background, buffer, 0, 0, 0, i*256 + shift, 800, 256);
	}

	for(int i =0; i<6;i++)
	{
		flowers[i]->Draw(buffer);
	}

	bottom->render(buffer);

	m_Player->Draw(buffer);

	for(int i = 0 ; i < 4 ; i++)
	{
		if(legs[i] != 0x0)
			legs[i]->draw(buffer);
	}

	rectfill(buffer, 0, 0, SCREEN_W, 12, makecol(0,0,0));
	textout_ex(buffer,font,statusString.c_str(),2,2 ,makecol(255,255,255),-1);

	textout_ex(buffer,font,"Lives:",240,2 ,makecol(255,255,255),-1);
	textout_ex(buffer,font,intToString(m_Player->lives).c_str(),290,2 ,makecol(255,0,0),-1);

}

//----------------------------------------------------------------------

void Application::updateGameOver()
{
	if(key[KEY_SPACE] || key[KEY_ENTER] || joy[0].button[9].b)
		setState(GAME);

	if(key[KEY_ESC])
		running = false;
}

//----------------------------------------------------------------------

void Application::drawGameOver()
{
	std::string msg = "You have managed to get to " + intToString((int)currentHeight/10);

	textout_centre_ex(buffer,font,"GAME OVER!",SCREEN_W/2,SCREEN_H/2 - 10,makecol(255,255,255),-1);
	textout_centre_ex(buffer,font,msg.c_str(),SCREEN_W/2,SCREEN_H/2 + 10,makecol(255,255,255),-1);
	textout_centre_ex(buffer,font,"To play again press START",SCREEN_W/2,SCREEN_H/2 + 20,makecol(255,255,255),-1);
}

//----------------------------------------------------------------------


